package com.example.threadmodel;

import com.example.threadmodel.model.Action;
import com.example.threadmodel.model.Student;
import com.example.threadmodel.service.HashThreadManagerService;
import com.example.threadmodel.service.ThreadManagerService;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * 结论：
 *  多一层队列，取任务到执行，可能会引起cpu缓存cache miss是有开销的
 *  开销：(570-9)/(32*1000)=0.0178ms
 */
@Slf4j
@SpringBootTest
public class Demo4_ManyPlayerQueueVsBindThreadSimpleTask {
    @Autowired
    private ThreadManagerService threadManagerService;

    @Autowired
    private HashThreadManagerService hashThreadManagerService;

    /**
     线程安全问题: 检测执行1000次后，是否金币数是1000
    ...
     2025-08-31 21:25:29 [INFO ] [main] c.e.t.Demo5_ThreadSafe.testQueue(Demo5_ThreadSafe.java:61) - student:Student(id=30, coinCount=1000)
     2025-08-31 21:25:29 [INFO ] [main] c.e.t.Demo5_ThreadSafe.testQueue(Demo5_ThreadSafe.java:61) - student:Student(id=31, coinCount=1000)
     2025-08-31 21:29:29 [INFO ] [main] c.e.t.Demo5_ThreadSafe.testQueue(Demo5_ThreadSafe.java:73) - costTime=570
     */
    @Test
    void testQueue() throws Exception {
        int studentNum = 32;
        int execCount = 1000;

        CountDownLatch countDownLatch = new CountDownLatch(studentNum * execCount);

        ConcurrentHashMap<String, Student> studentMap = new ConcurrentHashMap<>();
        for (int i = 0; i < studentNum; i++) {
            studentMap.put(i + "", new Student(i + "", 0));
        }

        long startTime = System.currentTimeMillis();

        for (int c = 0; c < studentNum; c++) {
            Student student = studentMap.get(c + "");

            // 每人执行1W次任务
            for (int i = 0; i < execCount; i++) {
                threadManagerService.enqueueAction(new Action<Integer>(student.getId(), () -> {
                    student.doSimpleLogic(student.getCoinCount() + 1);

                    countDownLatch.countDown();
                    return 0;
                }));
            }
        }

        // 等待确保执行完毕
        countDownLatch.await();

        long costTime = System.currentTimeMillis() - startTime;

        for (int c = 0; c < studentNum; c++) {
            Student student = studentMap.get(c + "");
            //log.info("student:{}", student);
        }

        log.info("costTime={}", costTime);

        TimeUnit.SECONDS.sleep(Long.MAX_VALUE);
    }

    /*
    2025-08-31 21:28:00 [WARN ] [main] c.e.t.Demo5_ThreadSafe.testThread(Demo5_ThreadSafe.java:116) - costTime=9
     */
    @Test
    void testBindThread() throws Exception {
        int studentNum = 32;
        int execCount = 100;

        CountDownLatch countDownLatch = new CountDownLatch(studentNum * execCount);

        ConcurrentHashMap<String, Student> studentMap = new ConcurrentHashMap<>();
        for (int i = 0; i < studentNum; i++) {
            studentMap.put(i + "", new Student(i + "", 0));
        }

        long startTime = System.currentTimeMillis();

        // 1000个学生
        for (int c = 0; c < studentNum; c++) {
            Student student = studentMap.get(c + "");

            // 每人执行1W次任务
            for (int i = 0; i < execCount; i++) {
                hashThreadManagerService.addTask(student.getId().hashCode(), () -> {
                    student.doSimpleLogic(student.getCoinCount() + 1);

                    countDownLatch.countDown();
                });
            }
        }

        // 等待3s，确保执行完毕
        countDownLatch.await();

        long costTime = System.currentTimeMillis() - startTime;

        for (int c = 0; c < studentNum; c++) {
            Student student = studentMap.get(c + "");
            //log.info("student:{}", student);
        }

        log.warn("costTime={}", costTime);

        TimeUnit.SECONDS.sleep(Long.MAX_VALUE);
    }
}
